package com.wx.common.sofabolt;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alipay.remoting.BizContext;
import com.alipay.remoting.Connection;
import com.alipay.remoting.ConnectionEventType;
import com.alipay.remoting.rpc.RpcServer;
import com.alipay.remoting.rpc.protocol.SyncUserProcessor;
import com.wx.common.exception.BizException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ConcurrentHashMap;

@Configuration
@ConditionalOnProperty(prefix = "sofabolt", name = "enable", havingValue = "true")
@RequiredArgsConstructor
@Slf4j
public class SofaboltServerConfig {
    private final SofaboltConfig sofaboltConfig;
    public static final ConcurrentHashMap<String, Connection> clientConnections = new ConcurrentHashMap<>();
    final NamingService namingService;

    @Bean
    public RpcServer rpcServer() {
        RpcServer server = null;
        try {
            // 创建 RPC 服务端
            server = new RpcServer(sofaboltConfig.getServerPort());

            // 注册处理器
            server.registerUserProcessor(new SyncUserProcessor<SofaboltMsgRequest>() {
                @Override
                public Object handleRequest(BizContext bizCtx, SofaboltMsgRequest request) throws Exception {
                    log.info("【收到客户端消息】: {}，消息：{}", bizCtx.getConnection().getChannel().id().asLongText(),
                            request.toString());
                    // 返回响应
                    return new SofaboltMsgResponse("Hello " + bizCtx.getConnection().getChannel().id().asLongText());
                }

                @Override
                public String interest() {
                    return SofaboltMsgRequest.class.getName();
                }
            });

            server.addConnectionEventProcessor(ConnectionEventType.CONNECT, (clientAddress, clientConnection) -> {
                // 保存客户端连接
                clientConnections.put(clientConnection.getChannel().id().asLongText(),
                        clientConnection);
                // 获取本地地址和端口
                InetSocketAddress localAddress = clientConnection.getLocalAddress();
                String localIp = localAddress.getAddress().getHostAddress();
                int localPort = localAddress.getPort();

                log.info("【与客户端-连接成功】: {}，客户端IP：{}，服务端本地IP和端口：{}:{}",
                        clientConnection.getChannel().id().asLongText(), clientAddress, localIp, localPort);
            });
            server.addConnectionEventProcessor(ConnectionEventType.CLOSE, (clientAddress, clientConnection) -> {
                clientConnections.remove(clientConnection.getChannel().id().asLongText());
                // 获取本地地址和端口
                InetSocketAddress localAddress = clientConnection.getLocalAddress();
                String localIp = localAddress.getAddress().getHostAddress();
                int localPort = localAddress.getPort();

                log.info("【与客户端-连接断开】: {}，客户端IP：{}，服务端本地IP和端口：{}:{}",
                        clientConnection.getChannel().id().asLongText(), clientAddress, localIp, localPort);
            });
            // 启动服务端
            server.startup();
            log.info("Sofabolt Server started on port {}", sofaboltConfig.getServerPort());
            registerService();
        } catch (
                Exception e) {
            throw new BizException("Failed to start sofabolt server", e);
        }
        return server;
    }

    /**
     * 注册服务到nacos
     */
    private void registerService() throws NacosException, UnknownHostException {
        Instance instance = new Instance();
        instance.setIp(InetAddress.getLocalHost().getHostAddress());
        instance.setPort(sofaboltConfig.getServerPort());
        instance.setHealthy(true);
        namingService.registerInstance(sofaboltConfig.getServerName(), sofaboltConfig.getServerGroup(), instance);
    }
}
